﻿using Sustainalytics.ClientDW.Synchronization.RiskRatingsBenchmarks;
using Sustainalytics.Entities.RiskRatings;
using System;
using System.Linq;
using Xunit;

namespace Sustainalytics.Benchmarkings.Tests
{
    [Trait("Category", "Unit")]
    public class ComparativeGroupTests : IClassFixture<ComparativeGroupFixture>
    {
        private readonly ComparativeGroupFixture _fixture;

        private readonly ComparativeGroup<RiskRatingResearchProfile, Guid, int> _sut;

        public ComparativeGroupTests(ComparativeGroupFixture fixture)
        {
            _fixture = fixture;
            _sut = ComparativeGroup<RiskRatingResearchProfile, Guid, int>.Create(_fixture.GetCorporateData(), x => x.Id, x => x.CompanyName, x => x.SubPeerGroupId, new SubPeerGroupComparer(), x => x.ManagementRisk.UnmanagedRisk.Value, new DoubleComparer());
        }

        [Fact]
        public void Count_Should_Return_Companies_Count()
        {
            //Arrange

            //Act
            var actual = _sut.Count;
            //Assert
            Assert.Equal(_fixture.Count, actual);
        }

        [Fact]
        public void GetAverage_should_return_Average_on_Companies_Count_In_Comparative_Group()
        {
            var actual = _sut.GetBenchmark(_fixture.GetCompanyIdByIndex(0));

            var corporateData = _fixture.GetCompanyByIndex(0);

            var expected = _fixture.GetCorporateData().Where(c => c.SubPeerGroupId == corporateData.SubPeerGroupId).Average(x => x.ManagementRisk.UnmanagedRisk.Value);

            Assert.Equal(expected, actual.Average,7);
        }

        [Fact]
        public void GetGroupCount_should_return_Companies_Count_In_Comparative_Group()
        {
            var actual = _sut.GetBenchmark(_fixture.GetCompanyIdByIndex(0));

            var corporateData = _fixture.GetCompanyByIndex(0);

            var expected = _fixture.GetCorporateData().Count(c => c.SubPeerGroupId == corporateData.SubPeerGroupId);

            Assert.Equal(expected, actual.Count);
        }

        [Fact]
        public void GetGroupIndex_shouldReturn_GroupId()
        {
            var actual = _sut.GetGroupIndex(_fixture.GetCompanyIdByIndex(0));

            var orderedData = _fixture.GetCorporateData().OrderBy(x => x.SubPeerGroupId).ToArray();

            var expected = Array.FindIndex(_fixture.GetSubPeerGroups(), y => y == orderedData.FirstOrDefault(x => x.Id == _fixture.GetCompanyIdByIndex(0)).SubPeerGroupId);

            Assert.Equal(expected, actual);
        }

        [Fact]
        public void GetPercentile_should_return_Percentile_on_Companies_Count_In_Comparative_Group()
        {
            var actual = _sut.GetBenchmark(_fixture.GetCompanyIdByIndex(0));

            var corporateData = _fixture.GetCompanyByIndex(0);

            var orderedData = _fixture.GetCorporateData().Where(c => c.SubPeerGroupId == corporateData.SubPeerGroupId).OrderBy(x => x.ManagementRisk.UnmanagedRisk.Value).ToArray();

            var expectedRank = Array.FindIndex(orderedData, x => x.Id == _fixture.GetCompanyIdByIndex(0)) + 1;

            var expected = ((((double)expectedRank - 1) / (orderedData.Count() - 1)) * 0.99) + 0.01;

            Assert.Equal(expected, actual.Percentile);
        }

        [Fact]
        public void GetRank_should_return_Rank_on_Companies_Count_In_Comparative_Group()
        {
            var actual = _sut.GetBenchmark(_fixture.GetCompanyIdByIndex(0));

            var corporateData = _fixture.GetCompanyByIndex(0);

            var orderedData = _fixture.GetCorporateData().Where(c => c.SubPeerGroupId == corporateData.SubPeerGroupId).OrderBy(x => x.ManagementRisk.UnmanagedRisk.Value).ToArray();

            var expected = Array.FindIndex(orderedData, x => x.Id == _fixture.GetCompanyIdByIndex(0)) + 1;

            Assert.Equal(expected, actual.Rank);
        }

        [Fact]
        public void GetRank_should_return_SameRank_as_Count_Companies_WithSameScore_In_Comparative_Group()
        {
            var companyPeers = _fixture.GetCorporateData().Where(c => c.SubPeerGroupId == _fixture.GetSubPeerGroupIdByIndex(1));

            var orderedData = companyPeers.OrderBy(x => x.ManagementRisk.UnmanagedRisk.Value).Last().Id;

            var actual = _sut.GetBenchmark(orderedData);

            Assert.Equal(companyPeers.Count(), actual.Rank);
        }

        [Fact]
        public void GetRank_should_return_SameRank_on_Companies_WithSameScore_In_Comparative_Group()
        {
            var corporateData = _fixture.GetCompanyByIndex(4);

            var actual = _sut.GetBenchmark(corporateData.Id);

            var orderedData = _fixture.GetCorporateData().FirstOrDefault(c => c.SubPeerGroupId == corporateData.SubPeerGroupId &&  Math.Abs(c.ManagementRisk.UnmanagedRisk.Value - corporateData.ManagementRisk.UnmanagedRisk.Value)<1e-16 && c.Id != corporateData.Id).Id;

            var expected = _sut.GetBenchmark(orderedData);

            Assert.Equal(expected.Rank, actual.Rank);
        }


       
    }
}